home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / DDJ0192.ARJ / TEXTBOX.C < prev    next >
Text File  |  1991-10-22  |  28KB  |  864 lines

  1. /* ------------- textbox.c ------------ */
  2.  
  3. #include "dflat.h"
  4.  
  5. static void ComputeWindowTop(WINDOW);
  6. static void ComputeWindowLeft(WINDOW);
  7. static int ComputeVScrollBox(WINDOW);
  8. static int ComputeHScrollBox(WINDOW);
  9. static void MoveScrollBox(WINDOW, int);
  10. static char *GetTextLine(WINDOW, int);
  11.  
  12. int VSliding;
  13. int HSliding;
  14.  
  15. /* ------------ ADDTEXT Message -------------- */
  16. static void AddTextMsg(WINDOW wnd, PARAM p1)
  17. {
  18.     /* --- append text to the textbox's buffer --- */
  19.     unsigned adln = strlen((char *)p1);
  20.     if (adln > (unsigned)0xfff0)
  21.         return;
  22.     if (wnd->text != NULL)    {
  23.         /* ---- appending to existing text ---- */
  24.         unsigned txln = strlen(wnd->text);
  25.         if ((long)txln+adln > (unsigned) 0xfff0)
  26.             return;
  27.         if (txln+adln > wnd->textlen)    {
  28.             wnd->text = realloc(wnd->text, txln+adln+3);
  29.             wnd->textlen = txln+adln+1;
  30.         }
  31.     }
  32.     else    {
  33.         /* ------ 1st text appended ------ */
  34.         wnd->text = calloc(1, adln+3);
  35.         wnd->textlen = adln+1;
  36.     }
  37.     if (wnd->text != NULL)    {
  38.         /* ---- append the text ---- */
  39.         strcat(wnd->text, (char*) p1);
  40.         strcat(wnd->text, "\n");
  41.         BuildTextPointers(wnd);
  42.     }
  43. }
  44.  
  45. /* ------------ SETTEXT Message -------------- */
  46. static void SetTextMsg(WINDOW wnd, PARAM p1)
  47. {
  48.     /* -- assign new text value to textbox buffer -- */
  49.     char *cp;
  50.     unsigned int len;
  51.     cp = (void *) p1;
  52.     len = strlen(cp)+1;
  53.     if (wnd->text == NULL || wnd->textlen < len)    {
  54.         wnd->textlen = len;
  55.         if ((wnd->text=realloc(wnd->text, len+1)) == NULL)
  56.             return;
  57.         wnd->text[len] = '\0';
  58.     }
  59.     strcpy(wnd->text, cp);
  60.     BuildTextPointers(wnd);
  61. }
  62.  
  63. /* ------------ CLEARTEXT Message -------------- */
  64. static void ClearTextMsg(WINDOW wnd)
  65. {
  66.     /* ----- clear text from textbox ----- */
  67.     if (wnd->text != NULL)
  68.         free(wnd->text);
  69.     wnd->text = NULL;
  70.     wnd->textlen = 0;
  71.     wnd->wlines = 0;
  72.     wnd->textwidth = 0;
  73.     wnd->wtop = wnd->wleft = 0;
  74.     ClearTextBlock(wnd);
  75.     ClearTextPointers(wnd);
  76. }
  77.  
  78. /* ------------ KEYBOARD Message -------------- */
  79. static int KeyboardMsg(WINDOW wnd, PARAM p1)
  80. {
  81.     switch ((int) p1)    {
  82.         case UP:
  83.             return SendMessage(wnd,SCROLL,FALSE,0);
  84.         case DN:
  85.             return SendMessage(wnd,SCROLL,TRUE,0);
  86.         case FWD:
  87.             return SendMessage(wnd,HORIZSCROLL,TRUE,0);
  88.         case BS:
  89.             return SendMessage(wnd,HORIZSCROLL,FALSE,0);
  90.         case PGUP:
  91.             return SendMessage(wnd,SCROLLPAGE,FALSE,0);
  92.         case PGDN:
  93.             return SendMessage(wnd,SCROLLPAGE,TRUE,0);
  94.         case CTRL_PGUP:
  95.             return SendMessage(wnd,HORIZPAGE,FALSE,0);
  96.         case CTRL_PGDN:
  97.             return SendMessage(wnd,HORIZPAGE,TRUE,0);
  98.         case HOME:
  99.             return SendMessage(wnd,SCROLLDOC,TRUE,0);
  100.         case END:
  101.             return SendMessage(wnd,SCROLLDOC,FALSE,0);
  102.         default:
  103.             break;
  104.     }
  105.     return FALSE;
  106. }
  107.  
  108. /* ------------ LEFT_BUTTON Message -------------- */
  109. static int LeftButtonMsg(WINDOW wnd, PARAM p1, PARAM p2)
  110. {
  111.     int mx = (int) p1 - GetLeft(wnd);
  112.     int my = (int) p2 - GetTop(wnd);
  113.     if (TestAttribute(wnd, VSCROLLBAR) &&
  114.                         mx == WindowWidth(wnd)-1)    {
  115.         /* -------- in the right border ------- */
  116.         if (my == 0 || my == ClientHeight(wnd)+1)
  117.             /* --- above or below the scroll bar --- */
  118.             return FALSE;
  119.         if (my == 1)
  120.             /* -------- top scroll button --------- */
  121.             return SendMessage(wnd, SCROLL, FALSE, 0);
  122.         if (my == ClientHeight(wnd))
  123.             /* -------- bottom scroll button --------- */
  124.             return SendMessage(wnd, SCROLL, TRUE, 0);
  125.         /* ---------- in the scroll bar ----------- */
  126.         if (!VSliding && my-1 == wnd->VScrollBox)    {
  127.             RECT rc;
  128.             VSliding = TRUE;
  129.             rc.lf = rc.rt = GetRight(wnd);
  130.             rc.tp = GetTop(wnd)+2;
  131.             rc.bt = GetBottom(wnd)-2;
  132.             return SendMessage(NULL, MOUSE_TRAVEL,
  133.                 (PARAM) &rc, 0);
  134.         }
  135.         if (my-1 < wnd->VScrollBox)
  136.             return SendMessage(wnd,SCROLLPAGE,FALSE,0);
  137.         if (my-1 > wnd->VScrollBox)
  138.             return SendMessage(wnd,SCROLLPAGE,TRUE,0);
  139.     }
  140.     if (TestAttribute(wnd, HSCROLLBAR) &&
  141.                         my == WindowHeight(wnd)-1) {
  142.         /* -------- in the bottom border ------- */
  143.         if (mx == 0 || my == ClientWidth(wnd)+1)
  144.             /* ------  outside the scroll bar ---- */
  145.             return FALSE;
  146.         if (mx == 1)
  147.             return SendMessage(wnd, HORIZSCROLL,FALSE,0);
  148.         if (mx == WindowWidth(wnd)-2)
  149.             return SendMessage(wnd, HORIZSCROLL,TRUE,0);
  150.         if (!HSliding && mx-1 == wnd->HScrollBox)    {
  151.             /* --- hit the scroll box --- */
  152.             RECT rc;
  153.             rc.lf = GetLeft(wnd)+2;
  154.             rc.rt = GetRight(wnd)-2;
  155.             rc.tp = rc.bt = GetBottom(wnd);
  156.             /* - keep the mouse in the scroll bar - */
  157.             SendMessage(NULL,MOUSE_TRAVEL,(PARAM)&rc,0);
  158.             HSliding = TRUE;
  159.             return TRUE;
  160.         }
  161.         if (mx-1 < wnd->HScrollBox)
  162.             return SendMessage(wnd,HORIZPAGE,FALSE,0);
  163.         if (mx-1 > wnd->HScrollBox)
  164.             return SendMessage(wnd,HORIZPAGE,TRUE,0);
  165.     }
  166.     return FALSE;
  167. }
  168.  
  169. /* ------------ MOUSE_MOVED Message -------------- */
  170. static int MouseMovedMsg(WINDOW wnd, PARAM p1, PARAM p2)
  171. {
  172.     int mx = (int) p1 - GetLeft(wnd);
  173.     int my = (int) p2 - GetTop(wnd);
  174.     if (VSliding)    {
  175.         /* ---- dragging the vertical scroll box --- */
  176.         if (my-1 != wnd->VScrollBox)    {
  177.             foreground = FrameForeground(wnd);
  178.             background = FrameBackground(wnd);
  179.             wputch(wnd, SCROLLBARCHAR, WindowWidth(wnd)-1,
  180.                     wnd->VScrollBox+1);
  181.             wnd->VScrollBox = my-1;
  182.             wputch(wnd, SCROLLBOXCHAR, WindowWidth(wnd)-1,
  183.                     my);
  184.         }
  185.         return TRUE;
  186.     }
  187.     if (HSliding)    {
  188.         /* --- dragging the horizontal scroll box --- */
  189.         if (mx-1 != wnd->HScrollBox)    {
  190.             foreground = FrameForeground(wnd);
  191.             background = FrameBackground(wnd);
  192.             wputch(wnd, SCROLLBARCHAR, wnd->HScrollBox+1,
  193.                     WindowHeight(wnd)-1);
  194.             wnd->HScrollBox = mx-1;
  195.             wputch(wnd, SCROLLBOXCHAR, mx, WindowHeight(wnd)-1);
  196.         }
  197.         return TRUE;
  198.     }
  199.     return FALSE;
  200. }
  201.  
  202. /* ------------ BUTTON_RELEASED Message -------------- */
  203. static void ButtonReleasedMsg(WINDOW wnd)
  204. {
  205.     if (HSliding || VSliding)    {
  206.         /* release the mouse ouside the scroll bar */
  207.         SendMessage(NULL, MOUSE_TRAVEL, 0, 0);
  208.         VSliding ? ComputeWindowTop(wnd):ComputeWindowLeft(wnd);
  209.         SendMessage(wnd, PAINT, 0, 0);
  210.         SendMessage(wnd, KEYBOARD_CURSOR, 0, 0);
  211.         VSliding = HSliding = FALSE;
  212.     }
  213. }
  214.  
  215. /* ------------ SCROLL Message -------------- */
  216. static int ScrollMsg(WINDOW wnd, PARAM p1)
  217. {
  218.     /* ---- vertical scroll one line ---- */
  219.     if (p1)    {
  220.         /* ----- scroll one line up ----- */
  221.         if (wnd->wtop+ClientHeight(wnd) >= wnd->wlines)
  222.             return FALSE;
  223.         wnd->wtop++;
  224.     }
  225.     else    {
  226.         /* ----- scroll one line down ----- */
  227.         if (wnd->wtop == 0)
  228.             return FALSE;
  229.         --wnd->wtop;
  230.     }
  231.     if (isVisible(wnd))    {
  232.         RECT rc;
  233.         rc = ClipRectangle(wnd, ClientRect(wnd));
  234.         if (ValidRect(rc))    {
  235.             /* ---- scroll the window ----- */
  236.             if (wnd != inFocus)    {
  237.                 int sv = ClipString;
  238.                 ClipString = TRUE;
  239.                 SendMessage(wnd, PAINT, 0, 0);
  240.                 ClipString = sv;
  241.             }
  242.             else    {
  243.                 scroll_window(wnd, rc, (int)p1);
  244.                 if (!(int)p1)
  245.                     /* -- write top line (down) -- */
  246.                     WriteTextLine(wnd,NULL,wnd->wtop,FALSE);
  247.                 else    {
  248.                     /* -- write bottom line (up) -- */
  249.                     int y=RectBottom(rc)-GetClientTop(wnd);
  250.                     WriteTextLine(wnd, NULL,
  251.                         wnd->wtop+y, FALSE);
  252.                 }
  253.             }
  254.         }
  255.         /* ---- reset the scroll box ---- */
  256.         if (TestAttribute(wnd, VSCROLLBAR))    {
  257.             int vscrollbox = ComputeVScrollBox(wnd);
  258.             if (vscrollbox != wnd->VScrollBox)
  259.                 MoveScrollBox(wnd, vscrollbox);
  260.         }
  261.         return TRUE;
  262.     }
  263.     return FALSE;
  264. }
  265.  
  266. /* ------------ HORIZSCROLL Message -------------- */
  267. static int HorizScrollMsg(WINDOW wnd, PARAM p1)
  268. {
  269.     /* --- horizontal scroll one column --- */
  270.     if (p1)    {
  271.         /* --- scroll left --- */
  272.         if (wnd->wleft + ClientWidth(wnd)-1 >= wnd->textwidth)
  273.             return FALSE;
  274.         wnd->wleft++;
  275.     }
  276.     else    {
  277.         /* --- scroll right --- */
  278.         if (wnd->wleft == 0)
  279.             return FALSE;
  280.         --wnd->wleft;
  281.     }
  282.     SendMessage(wnd, PAINT, 0, 0);
  283.     return TRUE;
  284. }
  285.  
  286. /* ------------  SCROLLPAGE Message -------------- */
  287. static void ScrollPageMsg(WINDOW wnd, PARAM p1)
  288. {
  289.     /* --- vertical scroll one page --- */
  290.     if ((int) p1 == FALSE)    {
  291.         /* ---- page up ---- */
  292.         if (wnd->wtop)    {
  293.             wnd->wtop -= ClientHeight(wnd);
  294.             if (wnd->wtop < 0)
  295.                 wnd->wtop = 0;
  296.         }
  297.     }
  298.     else     {
  299.         /* ---- page down ---- */
  300.         if (wnd->wtop+ClientHeight(wnd) < wnd->wlines) {
  301.             wnd->wtop += ClientHeight(wnd);
  302.             if (wnd->wtop>wnd->wlines-ClientHeight(wnd))
  303.                 wnd->wtop=wnd->wlines-ClientHeight(wnd);
  304.         }
  305.     }
  306.     SendMessage(wnd, PAINT, 0, 0);
  307. }
  308.  
  309. /* ------------ HORIZSCROLLPAGE Message -------------- */
  310. static void HorizScrollPageMsg(WINDOW wnd, PARAM p1)
  311. {
  312.     /* --- horizontal scroll one page --- */
  313.     if ((int) p1 == FALSE)    {
  314.         /* ---- page left ----- */
  315.         wnd->wleft -= ClientWidth(wnd);
  316.         if (wnd->wleft < 0)
  317.             wnd->wleft = 0;
  318.     }
  319.     else    {
  320.         /* ---- page right ----- */
  321.         wnd->wleft += ClientWidth(wnd);
  322.         if (wnd->wleft>wnd->textwidth-ClientWidth(wnd))
  323.             wnd->wleft=wnd->textwidth-ClientWidth(wnd);
  324.     }
  325.     SendMessage(wnd, PAINT, 0, 0);
  326. }
  327.  
  328. /* ------------ SCROLLDOC Message -------------- */
  329. static void ScrollDocMsg(WINDOW wnd, PARAM p1)
  330. {
  331.     /* --- scroll to beginning or end of document --- */
  332.     if ((int) p1)
  333.         wnd->wtop = wnd->wleft = 0;
  334.     else if (wnd->wtop+ClientHeight(wnd) < wnd->wlines){
  335.         wnd->wtop = wnd->wlines-ClientHeight(wnd);
  336.         wnd->wleft = 0;
  337.     }
  338.     SendMessage(wnd, PAINT, 0, 0);
  339. }
  340.  
  341. /* ------------ PAINT Message -------------- */
  342. static int PaintMsg(WINDOW wnd, PARAM p1)
  343. {
  344.     /* ------ paint the client area ----- */
  345.     RECT rc, rcc;
  346.     int y;
  347.     char blankline[201];
  348.  
  349.     /* ----- build the rectangle to paint ----- */
  350.     if ((RECT *)p1 == NULL)
  351.         rc=RelativeWindowRect(wnd, WindowRect(wnd));
  352.     else
  353.         rc= *(RECT *)p1;
  354.     if (TestAttribute(wnd, HASBORDER) &&
  355.             RectRight(rc) >= WindowWidth(wnd)-1) {
  356.         if (RectLeft(rc) >= WindowWidth(wnd)-1)
  357.             return FALSE;
  358.         RectRight(rc) = WindowWidth(wnd)-2;
  359.     }
  360.     rcc = AdjustRectangle(wnd, rc);
  361.  
  362.     /* ----- blank line for padding ----- */
  363.     memset(blankline, ' ', SCREENWIDTH);
  364.     blankline[RectRight(rcc)+1] = '\0';
  365.  
  366.     /* ------- each line within rectangle ------ */
  367.     for (y = RectTop(rc); y <= RectBottom(rc); y++){
  368.         int yy;
  369.         /* ---- test outside of Client area ---- */
  370.         if (TestAttribute(wnd,
  371.                     HASBORDER | HASTITLEBAR))    {
  372.             if (y < TopBorderAdj(wnd))
  373.                 continue;
  374.             if (y > WindowHeight(wnd)-2)
  375.                 continue;
  376.         }
  377.         yy = y-TopBorderAdj(wnd);
  378.         if (yy < wnd->wlines-wnd->wtop)
  379.             /* ---- paint a text line ---- */
  380.             WriteTextLine(wnd, &rc,
  381.                         yy+wnd->wtop, FALSE);
  382.         else    {
  383.             /* ---- paint a blank line ---- */
  384.             SetStandardColor(wnd);
  385.             writeline(wnd, blankline+RectLeft(rcc),
  386.                     RectLeft(rcc)+1, y, FALSE);
  387.         }
  388.     }
  389.     /* ------- position the scroll box ------- */
  390.     if (TestAttribute(wnd, VSCROLLBAR|HSCROLLBAR)) {
  391.         int hscrollbox = ComputeHScrollBox(wnd);
  392.         int vscrollbox = ComputeVScrollBox(wnd);
  393.         if (hscrollbox != wnd->HScrollBox ||
  394.                 vscrollbox != wnd->VScrollBox)    {
  395.             wnd->HScrollBox = hscrollbox;
  396.             wnd->VScrollBox = vscrollbox;
  397.             SendMessage(wnd, BORDER, p1, 0);
  398.         }
  399.     }
  400.     return TRUE;
  401. }
  402.  
  403. /* ------------ CLOSE_WINDOW Message -------------- */
  404. static void CloseWindowMsg(WINDOW wnd)
  405. {
  406.     SendMessage(wnd, CLEARTEXT, 0, 0);
  407.     if (wnd->TextPointers != NULL)    {
  408.         free(wnd->TextPointers);
  409.         wnd->TextPointers = NULL;
  410.     }
  411. }
  412.  
  413. /* ----------- TEXTBOX Message-processing Module ----------- */
  414. int TextBoxProc(WINDOW wnd, MESSAGE msg, PARAM p1, PARAM p2)
  415. {
  416.     switch (msg)    {
  417.         case CREATE_WINDOW:
  418.             wnd->HScrollBox = wnd->VScrollBox = 1;
  419.             ClearTextPointers(wnd);
  420.             break;
  421.         case ADDTEXT:
  422.             AddTextMsg(wnd, p1);
  423.             break;
  424.         case SETTEXT:
  425.             SetTextMsg(wnd, p1);
  426.             break;
  427.         case CLEARTEXT:
  428.             ClearTextMsg(wnd);
  429.             break;
  430.         case KEYBOARD:
  431.             if (WindowMoving || WindowSizing)
  432.                 break;
  433.             if (KeyboardMsg(wnd, p1))
  434.                 return TRUE;
  435.             break;
  436.         case LEFT_BUTTON:
  437.             if (WindowSizing || WindowMoving)
  438.                 return FALSE;
  439.             if (LeftButtonMsg(wnd, p1, p2))
  440.                 return TRUE;
  441.             break;
  442.         case MOUSE_MOVED:
  443.             if (MouseMovedMsg(wnd, p1, p2))
  444.                 return TRUE;
  445.             break;
  446.         case BUTTON_RELEASED:
  447.             ButtonReleasedMsg(wnd);
  448.             break;
  449.         case SCROLL:
  450.             return ScrollMsg(wnd, p1);
  451.         case HORIZSCROLL:
  452.             return HorizScrollMsg(wnd, p1);
  453.         case SCROLLPAGE:
  454.             ScrollPageMsg(wnd, p1);
  455.             return TRUE;
  456.         case HORIZPAGE:
  457.             HorizScrollPageMsg(wnd, p1);
  458.             return TRUE;
  459.         case SCROLLDOC:
  460.             ScrollDocMsg(wnd, p1);
  461.             return TRUE;
  462.         case PAINT:
  463.             if (isVisible(wnd) && wnd->wlines)    {
  464.                 PaintMsg(wnd, p1);
  465.                 return FALSE;
  466.             }
  467.             break;
  468.         case CLOSE_WINDOW:
  469.             CloseWindowMsg(wnd);
  470.             break;
  471.         default:
  472.             break;
  473.     }
  474.     return BaseWndProc(TEXTBOX, wnd, msg, p1, p2);
  475. }
  476.  
  477. /* ------ compute the vertical scroll box position from
  478.                    the text pointers --------- */
  479. static int ComputeVScrollBox(WINDOW wnd)
  480. {
  481.     int pagelen = wnd->wlines - ClientHeight(wnd);
  482.     int barlen = ClientHeight(wnd)-2;
  483.     int lines_tick;
  484.     int vscrollbox;
  485.  
  486.     if (pagelen < 1 || barlen < 1)
  487.         vscrollbox = 1;
  488.     else    {
  489.         if (pagelen > barlen)
  490.             lines_tick = pagelen / barlen;
  491.         else
  492.             lines_tick = barlen / pagelen;
  493.         vscrollbox = 1 + (wnd->wtop / lines_tick);
  494.         if (vscrollbox > ClientHeight(wnd)-2 ||
  495.                 wnd->wtop + ClientHeight(wnd) >= wnd->wlines)
  496.             vscrollbox = ClientHeight(wnd)-2;
  497.     }
  498.     return vscrollbox;
  499. }
  500.  
  501. /* ---- compute top text line from scroll box position ---- */
  502. static void ComputeWindowTop(WINDOW wnd)
  503. {
  504.     int pagelen = wnd->wlines - ClientHeight(wnd);
  505.     if (wnd->VScrollBox == 0)
  506.         wnd->wtop = 0;
  507.     else if (wnd->VScrollBox == ClientHeight(wnd)-2)
  508.         wnd->wtop = pagelen;
  509.     else    {
  510.         int barlen = ClientHeight(wnd)-2;
  511.         int lines_tick;
  512.  
  513.         if (pagelen > barlen)
  514.             lines_tick = pagelen / barlen;
  515.         else
  516.             lines_tick = barlen / pagelen;
  517.         wnd->wtop = (wnd->VScrollBox-1) * lines_tick;
  518.         if (wnd->wtop + ClientHeight(wnd) > wnd->wlines)
  519.             wnd->wtop = pagelen;
  520.     }
  521.     if (wnd->wtop < 0)
  522.         wnd->wtop = 0;
  523. }
  524.  
  525. /* ------ compute the horizontal scroll box position from
  526.                    the text pointers --------- */
  527. static int ComputeHScrollBox(WINDOW wnd)
  528. {
  529.     int pagewidth = wnd->textwidth - ClientWidth(wnd);
  530.     int barlen = ClientWidth(wnd)-2;
  531.     int chars_tick;
  532.     int hscrollbox;
  533.  
  534.     if (pagewidth < 1 || barlen < 1)
  535.         hscrollbox = 1;
  536.     else     {
  537.         if (pagewidth > barlen)
  538.             chars_tick = pagewidth / barlen;
  539.         else
  540.             chars_tick = barlen / pagewidth;
  541.         hscrollbox = 1 + (wnd->wleft / chars_tick);
  542.         if (hscrollbox > ClientWidth(wnd)-2 ||
  543.                 wnd->wleft + ClientWidth(wnd) >= wnd->textwidth)
  544.             hscrollbox = ClientWidth(wnd)-2;
  545.     }
  546.     return hscrollbox;
  547. }
  548.  
  549. /* ---- compute left column from scroll box position ---- */
  550. static void ComputeWindowLeft(WINDOW wnd)
  551. {
  552.     int pagewidth = wnd->textwidth - ClientWidth(wnd);
  553.  
  554.     if (wnd->HScrollBox == 0)
  555.         wnd->wleft = 0;
  556.     else if (wnd->HScrollBox == ClientWidth(wnd)-2)
  557.         wnd->wleft = pagewidth;
  558.     else    {
  559.         int barlen = ClientWidth(wnd)-2;
  560.         int chars_tick;
  561.  
  562.         if (pagewidth > barlen)
  563.             chars_tick = pagewidth / barlen;
  564.         else
  565.             chars_tick = barlen / pagewidth;
  566.         wnd->wleft = (wnd->HScrollBox-1) * chars_tick;
  567.         if (wnd->wleft + ClientWidth(wnd) > wnd->textwidth)
  568.             wnd->wleft = pagewidth;
  569.     }
  570.     if (wnd->wleft < 0)
  571.         wnd->wleft = 0;
  572. }
  573.  
  574. /* ----- get the text to a specified line ----- */
  575. static char *GetTextLine(WINDOW wnd, int selection)
  576. {
  577.     char *line;
  578.     int len = 0;
  579.     char *cp, *cp1;
  580.     cp = cp1 = TextLine(wnd, selection);
  581.     while (*cp && *cp != '\n')    {
  582.         len++;
  583.         cp++;
  584.     }
  585.     line = malloc(len+6);
  586.     if (line != NULL)    {
  587.         memmove(line, cp1, len);
  588.         line[len] = '\0';
  589.     }
  590.     return line;
  591. }
  592.  
  593. /* ------- write a line of text to a textbox window ------- */
  594. void WriteTextLine(WINDOW wnd, RECT *rcc, int y, int reverse)
  595. {
  596.     int len = 0;
  597.     int dif = 0;
  598.     unsigned char *line;
  599.     RECT rc;
  600.     unsigned char *lp, *svlp;
  601.     int lnlen;
  602.     int i;
  603.     int trunc = FALSE;
  604.  
  605.     /* ------ make sure y is inside the window ----- */
  606.     if (y < wnd->wtop || y >= wnd->wtop+ClientHeight(wnd))
  607.         return;
  608.  
  609.     /* ---- build the retangle within which can write ---- */
  610.     if (rcc == NULL)    {
  611.         rc = RelativeWindowRect(wnd, WindowRect(wnd));
  612.         if (TestAttribute(wnd, HASBORDER) &&
  613.                 RectRight(rc) >= WindowWidth(wnd)-1)
  614.             RectRight(rc) = WindowWidth(wnd)-2;
  615.     }
  616.     else
  617.         rc = *rcc;
  618.  
  619.     /* ----- make sure rectangle is within window ------ */
  620.     if (RectLeft(rc) >= WindowWidth(wnd)-1)
  621.         return;
  622.     if (RectRight(rc) == 0)
  623.         return;
  624.     rc = AdjustRectangle(wnd, rc);
  625.     if (y-wnd->wtop<RectTop(rc) || y-wnd->wtop>RectBottom(rc))
  626.         return;
  627.  
  628.     /* --- get the text and length of the text line --- */
  629.     lp = svlp = GetTextLine(wnd, y);
  630.     if (svlp == NULL)
  631.         return;
  632.     lnlen = LineLength(lp);
  633.  
  634.     /* -------- insert block color change controls ------- */
  635.     if (TextBlockMarked(wnd))    {
  636.         int bbl = wnd->BlkBegLine;
  637.         int bel = wnd->BlkEndLine;
  638.         int bbc = wnd->BlkBegCol;
  639.         int bec = wnd->BlkEndCol;
  640.         int by = y;
  641.  
  642.         /* ----- put lowest marker first ----- */
  643.         if (bbl > bel)    {
  644.             swap(bbl, bel);
  645.             swap(bbc, bec);
  646.         }
  647.         if (bbl == bel && bbc > bec)
  648.             swap(bbc, bec);
  649.  
  650.         if (by >= bbl && by <= bel)    {
  651.             /* ------ the block includes this line ----- */
  652.             int blkbeg = 0;
  653.             int blkend = lnlen;
  654.             if (!(by > bbl && by < bel))    {
  655.                 /* --- the entire line is not in the block -- */
  656.                 if (by == bbl)
  657.                     /* ---- the block begins on this line --- */
  658.                     blkbeg = bbc;
  659.                 if (by == bel)
  660.                     /* ---- the block ends on this line ---- */
  661.                     blkend = bec;
  662.             }
  663.             /* ----- insert the reset color token ----- */
  664.             memmove(lp+blkend+1,lp+blkend,strlen(lp+blkend)+1);
  665.             lp[blkend] = RESETCOLOR;
  666.             /* ----- insert the change color token ----- */
  667.             memmove(lp+blkbeg+3,lp+blkbeg,strlen(lp+blkbeg)+1);
  668.             lp[blkbeg] = CHANGECOLOR;
  669.             /* ----- insert the color tokens ----- */
  670.             SetReverseColor(wnd);
  671.             lp[blkbeg+1] = foreground | 0x80;
  672.             lp[blkbeg+2] = background | 0x80;
  673.             lnlen += 4;
  674.         }
  675.     }
  676.     /* - make sure left margin doesn't overlap color change - */
  677.     for (i = 0; i < wnd->wleft+3; i++)    {
  678.         if (*(lp+i) == '\0')
  679.             break;
  680.         if (*(unsigned char *)(lp + i) == RESETCOLOR)
  681.             break;
  682.     }
  683.     if (*(lp+i) && i < wnd->wleft+3)    {
  684.         if (wnd->wleft+4 > lnlen)
  685.             trunc = TRUE;
  686.         else 
  687.             lp += 4;
  688.     }
  689.     else     {
  690.         /* --- it does, shift the color change over --- */
  691.         for (i = 0; i < wnd->wleft; i++)    {
  692.             if (*(lp+i) == '\0')
  693.                 break;
  694.             if (*(unsigned char *)(lp + i) == CHANGECOLOR)    {
  695.                 *(lp+wnd->wleft+2) = *(lp+i+2);
  696.                 *(lp+wnd->wleft+1) = *(lp+i+1);
  697.                 *(lp+wnd->wleft) = *(lp+i);
  698.                 break;
  699.             }
  700.         }
  701.     }
  702.     /* ------ build the line to display -------- */
  703.     if ((line = malloc(200)) != NULL)    {
  704.         if (!trunc)    {
  705.             if (lnlen < wnd->wleft)
  706.                 lnlen = 0;
  707.             else
  708.                 lp += wnd->wleft;
  709.             if (lnlen > RectLeft(rc))    {
  710.                 /* ---- the line exceeds the rectangle ---- */
  711.                 int ct = RectLeft(rc);
  712.                 char *initlp = lp;
  713.                 /* --- point to end of clipped line --- */
  714.                 while (ct)    {
  715.                     if (*(unsigned char *)lp == CHANGECOLOR)
  716.                         lp += 3;
  717.                     else if (*(unsigned char *)lp == RESETCOLOR)
  718.                         lp++;
  719.                     else
  720.                         lp++, --ct;
  721.                 }
  722.                 if (RectLeft(rc))    {
  723.                     char *lpp = lp;
  724.                     while (*lpp)    {
  725.                         if (*(unsigned char*)lpp==CHANGECOLOR)
  726.                             break;
  727.                         if (*(unsigned char*)lpp==RESETCOLOR) {
  728.                             lpp = lp;
  729.                             while (lpp >= initlp)    {
  730.                                 if (*(unsigned char *)lpp ==
  731.                                                 CHANGECOLOR) {
  732.                                     lp -= 3;
  733.                                     memmove(lp,lpp,3);
  734.                                     break;
  735.                                 }
  736.                                 --lpp;
  737.                             }
  738.                             break;
  739.                         }
  740.                         lpp++;
  741.                     }
  742.                 }
  743.                 lnlen = LineLength(lp);
  744.                 len = min(lnlen, RectWidth(rc));
  745.                 dif = strlen(lp) - lnlen;
  746.                 len += dif;
  747.                 if (len > 0)
  748.                     strncpy(line, lp, len);
  749.             }
  750.         }
  751.         /* -------- pad the line --------- */
  752.         while (len < RectWidth(rc)+dif)
  753.             line[len++] = ' ';
  754.         line[len] = '\0';
  755.         dif = 0;
  756.         /* ------ establish the line's main color ----- */
  757.         if (reverse)    {
  758.             char *cp = line;
  759.             SetReverseColor(wnd);
  760.             while ((cp = strchr(cp, CHANGECOLOR)) != NULL)    {
  761.                 cp += 2;
  762.                 *cp++ = background | 0x80;
  763.             }
  764.             if (*(unsigned char *)line == CHANGECOLOR)
  765.                 dif = 3;
  766.         }
  767.         else
  768.             SetStandardColor(wnd);
  769.         /* ------- display the line -------- */
  770.         writeline(wnd, line+dif,
  771.                     RectLeft(rc)+BorderAdj(wnd),
  772.                         y-wnd->wtop+TopBorderAdj(wnd), FALSE);
  773.         free(line);
  774.     }
  775.     free(svlp);
  776. }
  777.  
  778. /* ----- set anchor point for marking text block ----- */
  779. void SetAnchor(WINDOW wnd, int mx, int my)
  780. {
  781.     if (TextBlockMarked(wnd))    {
  782.         ClearTextBlock(wnd);
  783.         SendMessage(wnd, PAINT, 0, 0);
  784.     }
  785.     /* ------ set the anchor ------ */
  786.     wnd->BlkBegLine = wnd->BlkEndLine = my;
  787.     wnd->BlkBegCol = wnd->BlkEndCol = mx;
  788. }
  789.  
  790. void MarkTextBlock(WINDOW wnd, int BegLine, int BegCol,
  791.                                int EndLine, int EndCol)
  792. {
  793.     wnd->BlkBegLine = BegLine;
  794.     wnd->BlkEndLine = EndLine;
  795.     wnd->BlkBegCol = BegCol;
  796.     wnd->BlkEndCol = EndCol;
  797. }
  798.  
  799. /* ----- clear and initialize text line pointer array ----- */
  800. void ClearTextPointers(WINDOW wnd)
  801. {
  802.     wnd->TextPointers = realloc(wnd->TextPointers, sizeof(int));
  803.     if (wnd->TextPointers != NULL)
  804.         *(wnd->TextPointers) = 0;
  805. }
  806.  
  807. #define INITLINES 100
  808.  
  809. /* ---- build array of pointers to text lines ---- */
  810. void BuildTextPointers(WINDOW wnd)
  811. {
  812.     char *cp = wnd->text, *cp1;
  813.     int incrs = INITLINES;
  814.     unsigned int off;
  815.     wnd->textwidth = wnd->wlines = 0;
  816.     while (*cp)    {
  817.         if (incrs == INITLINES)    {
  818.             incrs = 0;
  819.             wnd->TextPointers = realloc(wnd->TextPointers,
  820.                     (wnd->wlines + INITLINES) * sizeof(int));
  821.             if (wnd->TextPointers == NULL)
  822.                 break;
  823.         }
  824.         off = (unsigned int) (cp - wnd->text);
  825.         *((wnd->TextPointers) + wnd->wlines) = off;
  826.         wnd->wlines++;
  827.         incrs++;
  828.         cp1 = cp;
  829.         while (*cp && *cp != '\n')
  830.             cp++;
  831.         wnd->textwidth = max(wnd->textwidth,
  832.                         (unsigned int) (cp - cp1));
  833.         if (*cp)
  834.             cp++;
  835.     }
  836. }
  837.  
  838. static void MoveScrollBox(WINDOW wnd, int vscrollbox)
  839. {
  840.     foreground = FrameForeground(wnd);
  841.     background = FrameBackground(wnd);
  842.     wputch(wnd, SCROLLBARCHAR, WindowWidth(wnd)-1,
  843.             wnd->VScrollBox+1);
  844.     wputch(wnd, SCROLLBOXCHAR, WindowWidth(wnd)-1,
  845.             vscrollbox+1);
  846.     wnd->VScrollBox = vscrollbox;
  847. }
  848.  
  849. int TextLineNumber(WINDOW wnd, char *lp)
  850. {
  851.     int lineno;
  852.     char *cp;
  853.     for (lineno = 0; lineno < wnd->wlines; lineno++)    {
  854.         cp = wnd->text + *((wnd->TextPointers) + lineno);
  855.         if (cp == lp)
  856.             return lineno;
  857.         if (cp > lp)
  858.             break;
  859.     }
  860.     return lineno-1;
  861. }
  862.  
  863.  
  864.